package it.kion.util.ui.ulog2;

import it.kion.util.ui.ulog2.Filter.TYPE;
import it.kion.util.ui.ulog2.editor.TokenManager;
import it.kion.util.ui.ulog2.views.Log4jView;

import java.io.IOException;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.jface.action.StatusLineContributionItem;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.views.IViewDescriptor;

public class Log4jPlugin extends AbstractUIPlugin {
	private static Log4jView res = null;
	private static Log4jPlugin plugin;
//	private static boolean serverRunning = false;
	private static Map<URL, ImageDescriptor> images = new HashMap<URL, ImageDescriptor>();
	private static boolean notAlreadyFoundByID = true;
	private ResourceBundle resourceBundle;
	private LoggingModel loggingModel;
	private TokenManager tokenManager;

	public static final String DEBUG_COLOR_KEY = "DEBUG_COLOR_KEY";

	public static final String INFO_COLOR_KEY = "INFO_COLOR_KEY";

	public static final String WARN_COLOR_KEY = "WARN_COLOR_KEY";

	public static final String ERROR_COLOR_KEY = "ERROR_COLOR_KEY";

	public static final String FATAL_COLOR_KEY = "FATAL_COLOR_KEY";

	public static final String DEBUG_COLOR_KEY_BG = "DEBUG_COLOR_KEY_BG";

	public static final String INFO_COLOR_KEY_BG = "INFO_COLOR_KEY_BG";

	public static final String WARN_COLOR_KEY_BG = "WARN_COLOR_KEY_BG";

	public static final String ERROR_COLOR_KEY_BG = "ERROR_COLOR_KEY_BG";

	public static final String FATAL_COLOR_KEY_BG = "FATAL_COLOR_KEY_BG";

	public static final String PREF_COMMENT_COLOR = "log4j_comment_color";
	public static final String PREF_PROPERTY_COLOR = "log4j_property_color";
	public static final String PREF_FORMAT_COLOR = "log4j_format_color";
	public static final String PREF_KEYWORD_COLOR = "log4j_keyword_color";
	public static final String PREF_DEFAULT_COLOR = "log4j_default_color";

	public static final String PREF_AUTOSTART = "log4j_automatic_start";

	public static final String PREF_PORT = "log4j_socket_server_port";
	public static final String PREF_DEFAULT_PORT = "18381";

	public static final String PREF_DETAIL_FORM_WIDTH = "logEventDialog_width";

	public static final String PREF_DETAIL_FORM_HEIGHT = "logEventDialog_height";

	public static final String LOG_OVERLAY = "icons/log4j_ovr.gif";
	
	public static final String DEBUG_ICO = "/icons/debug.gif";
	public static final String DEBUG_ICO_DISABLE = "/icons/debug_disab.gif";
	public static final String INFO_ICO = "/icons/info.gif";
	public static final String INFO_ICO_DISABLE = "/icons/info_disab.gif";
	public static final String WARN_ICO = "/icons/warning.gif";
	public static final String WARN_ICO_DISABLE = "/icons/warning_disab.gif";
	public static final String ERROR_ICO = "/icons/error.gif";
	public static final String ERROR_ICO_DISABLE = "/icons/error_disab.gif";
	public static final String FATAL_ICO = "/icons/fatal.gif";
	public static final String FATAL_ICO_DISABLE = "/icons/fatal_disab.gif";
	public static final String PAUSE_ICO = "/icons/pause.gif";
	public static final String RESUME_ICO = "/icons/start.gif";
	
	private static ReceiverThread RT = null;

	/**
	 * Accessor
	 * @return
	 * 		il RecieverThread che colleziona i log.
	 */
	public static ReceiverThread getRT() {
		return RT;
	}

	ULog2SocketNode receiverSocketNode;
	
	public static enum LEVELS {
		DEBUG,
		INFO,
		WARN,
		ERROR,
		FATAL
	};
	
	public static final Map<String, String> icons = new HashMap<String, String>(10) {

		private static final long serialVersionUID = -2317647082996513524L;

		{
			put("DEBUG", DEBUG_ICO);
			put("DEBUG_DISABLE", DEBUG_ICO_DISABLE);			
			put("INFO", INFO_ICO);
			put("INFO_DISABLE", INFO_ICO_DISABLE);			
			put("WARN", WARN_ICO);
			put("WARN_DISABLE", WARN_ICO_DISABLE);			
			put("ERROR", ERROR_ICO);
			put("ERROR_DISABLE", ERROR_ICO_DISABLE);			
			put("FATAL", FATAL_ICO);
			put("FATAL_DISABLE", FATAL_ICO_DISABLE);			
		}
	};

	public Log4jPlugin(IPluginDescriptor descriptor) {
		super(descriptor);
		plugin = this;

		try {
			resourceBundle = ResourceBundle
					.getBundle("it.kion.util.ui.ulog2.Log4jPluginResources");
		} catch (MissingResourceException x) {
			resourceBundle = null;
		}

		tokenManager = new TokenManager(getPreferenceStore());
		loggingModel = new LoggingModel();
	}

	public static Log4jPlugin getDefault() {
		return plugin;
	}

	@Override
	public void startup() throws CoreException {
		loadPreferenceStore();
//		setupReceiver();
//		RT.start();
//		String msg = "U-Log2 avviato correttamente sulla porta " + Log4jPlugin.getRT().getPort();
//		DebugPlugin.logDebugMessage(msg);
	}

	public static String getResourceString(String key) {
		ResourceBundle bundle = Log4jPlugin.getDefault().getResourceBundle();
		try {
			return bundle.getString(key);
		} catch (MissingResourceException e) {
			return key;
		}
	}

	public void setupReceiver() {
		int port = getPreferenceStore().getInt(Log4jPlugin.PREF_PORT);
		setupReceiver(port);
//		try {
//			setupReceiver(port);
//		} catch (ThreadStartEcxeption te) {
//			// TODO
//		}
	}
	
	@Override
	protected void loadPreferenceStore() {
		Log4jPlugin.getDefault().getPreferenceStore();
	}
	
	public void setupReceiver(int port) {
		DebugPlugin.logDebugMessage("Setup di U-Log2 sulla porta " + port);
//		try {
//			if(RT!=null && RT.isAlive()) {
//				RT.interrupt();
//			}
//			RT = new ReceiverThread(loggingModel, port);
//		} catch (IOException e) {
//			MessageDialog.openWarning(getWorkbench().getActiveWorkbenchWindow().getShell(), "U-Log2 - Problema nella creazione del thread collettore dei log!", e.getMessage());
//			DebugPlugin.log(e);
//			throw new ThreadStartEcxeption(e);
//		}
		try {
			Socket client = new Socket("localhost", port);
			if(receiverSocketNode!=null) {
				receiverSocketNode.stop();
			}
			receiverSocketNode = new ULog2SocketNode(client, loggingModel);
			receiverSocketNode.start();
		} catch (UnknownHostException e) {
		} catch (IOException e) {
			MessageDialog.openWarning(getWorkbench().getActiveWorkbenchWindow().getShell(), "U-Log2", "Problemi nell'apertura della socket lato client: assicurarsi che il server di log sia attivo e riprovare.");
		}		
	}

	protected void initializeDefaultPreferences(IPreferenceStore store) {
		super.initializeDefaultPreferences(store);

		store.setDefault(Log4jPlugin.PREF_COMMENT_COLOR, StringConverter
				.asString(new RGB(63, 127, 95)));
		store.setDefault(Log4jPlugin.PREF_FORMAT_COLOR, StringConverter
				.asString(new RGB(255, 0, 42)));
		store.setDefault(Log4jPlugin.PREF_DEFAULT_COLOR, StringConverter
				.asString(new RGB(0, 0, 0)));
		store.setDefault(Log4jPlugin.PREF_KEYWORD_COLOR, StringConverter
				.asString(new RGB(127, 0, 85)));
		store.setDefault(Log4jPlugin.PREF_PROPERTY_COLOR, StringConverter
				.asString(new RGB(85, 85, 127)));

		store.setDefault(Log4jPlugin.PREF_PORT, 4445);
	}

	public void shutdown() throws CoreException {
		super.shutdown();
		tokenManager.dispose();
		receiverSocketNode.stop();
	}

	public ResourceBundle getResourceBundle() {
		return resourceBundle;
	}

	public LoggingModel getLoggingModel() {
		return loggingModel;
	}

	public TokenManager getTokenManager() {
		return tokenManager;
	}

	public static ImageDescriptor getImageDescriptor(String path) {
		URL url = getDefault().find(new Path(path));
		if (url != null) {
			if(images.get(url)==null) {
				images.put(url, ImageDescriptor.createFromURL(url));
			}
			return images.get(url);
		}
		return null;
	}

	public static boolean isPaused() {
		return RT.isPaused();
	}
	
	public boolean isLevelEnabled(String string) {
		boolean res = true;
		Filter[] fs = loggingModel.getFilterSet().getFilters();
		List<Filter> list = new ArrayList<Filter>(Arrays.asList(fs));
		Filter template = new Filter(TYPE.LEVEL, string, false);
		if (list.contains(template)) {
			res = false;
		}
		else {
			res = true;
		}
		return res;
	}
	
	public void enableLevelFor(String liv) {
		Filter[] fs = loggingModel.getFilterSet().getFilters();
		List<Filter> list = new ArrayList<Filter>(Arrays.asList(fs));
		Filter template = new Filter(TYPE.LEVEL, liv, false);
		if (list.contains(template)) {
			loggingModel.getFilterSet().removeFilter(template);
		}
	}

	public void disableLevelFor(String liv) {
		Filter[] fs = loggingModel.getFilterSet().getFilters();
		List<Filter> list = Arrays.asList(fs);
		Filter template = new Filter(TYPE.LEVEL, liv, false);
		if (!list.contains(template)) {
			loggingModel.getFilterSet().addFilter(template);
		}
	}

	public static final String getIconPath(LEVELS level, boolean disabled) {
		String iconKey = level.toString() + (disabled ? "_DISABLE" : "");
		return icons.get(iconKey);
	}

	public static Log4jView getMainView() {
		if(res==null) {
			IViewDescriptor vd = PlatformUI.getWorkbench().getViewRegistry().find(Log4jView.ID);
			try {
				notAlreadyFoundByID = true;
				res = (Log4jView) vd.createView();
			} catch (CoreException e) {
			}			
		} else /*if(notAlreadyFoundByID)*/ {
			if( PlatformUI.getWorkbench()!=null
				&& PlatformUI.getWorkbench().getActiveWorkbenchWindow()!=null
				&& PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()!=null) {
				res = (Log4jView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(Log4jView.ID);
				notAlreadyFoundByID  = false;
			}
		}
		return res;
	}

	private static IViewSite mSite;

	public static IViewSite getMSite() {
		return mSite;
	}

	public static void setMSite(IViewSite site) {
		mSite = site;
	}

	public static int getListeningPort() {
		int port = -1;
		if(RT!=null) {
			port = RT.getPort();
		}
		return port;
	}
	
	public static void updateStatus(String text) {
		Log4jView mainView = getMainView();
		if(mainView!=null) {
			StatusLineContributionItem slci = mainView.getStatusLineContributionItem();
			if(slci!=null){
				slci.setText(text);
			}
		}
	}
	
	public boolean isConnected() {
		boolean res = false;
		res = receiverSocketNode!=null && receiverSocketNode.isAlive();
		return res;
	}
	
}
